home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / TCPOUT.C < prev    next >
C/C++ Source or Header  |  1989-08-11  |  6KB  |  206 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7. #include "ip.h"
  8.  
  9. /* Send a segment on the specified connection. One gets sent only
  10.  * if there is data to be sent or if "force" is non zero
  11.  */
  12. void
  13. tcp_output(tcb)
  14. register struct tcb *tcb;
  15. {
  16.     struct pseudo_header ph;/* Pseudo-header for checksum calcs */
  17.     struct mbuf *hbp,*dbp;    /* Header and data buffer pointers */
  18.     int16 hsize;        /* Size of header */
  19.     struct tcp seg;        /* Local working copy of header */
  20.     int16 ssize;        /* Size of current segment being sent,
  21.                  * including SYN and FIN flags */
  22.     int16 dsize;        /* Size of segment less SYN and FIN */
  23.     int16 usable;        /* Usable window */
  24.     int16 sent;        /* Sequence count (incl SYN/FIN) already in the pipe */
  25.  
  26.     if(tcb == NULLTCB)
  27.         return;
  28.  
  29.     switch(tcb->state){
  30.     case LISTEN:
  31.     case CLOSED:
  32.         return;    /* Don't send anything */
  33.     }
  34.     for(;;){
  35.         sent = tcb->snd.ptr - tcb->snd.una;
  36.  
  37. #ifdef    notdef
  38.         /* If this is a retransmission, send only the oldest segment
  39.          * (first-only retransmission policy) -- OBSOLETED by cwind
  40.          */
  41.         if(tcb->flags.retran && sent != 0)
  42.             break;
  43. #endif
  44.         /* Don't send anything else until our SYN has been acked */
  45.         if(sent != 0 && !tcb->flags.synack)
  46.             break;
  47.  
  48.         if(tcb->snd.wnd == 0){
  49.             /* Allow only one closed-window probe at a time */
  50.             if(sent != 0)
  51.                 break;
  52.             /* Force a closed-window probe */
  53.             usable = 1;
  54.         } else {
  55.             /* usable window = offered window - unacked bytes in transit
  56.              * limited by the congestion window
  57.              */
  58.             usable = min(tcb->snd.wnd,tcb->cwind) - sent;
  59.  
  60.             /* John Nagle's "single outstanding segment" rule.
  61.              * Allow only one segment in the pipeline unless there is enough
  62.              * unsent data to form at least one maximum-sized segment.
  63.              */
  64.             if(sent != 0 && tcb->sndcnt - sent < tcb->mss){
  65.                 usable = 0;
  66.             }
  67. #ifdef    notdef
  68.             /* Silly window avoidance. Don't send anything if the
  69.              * usable window is less than a quarter of the offered
  70.              * window. This test comes into play only when the
  71.              * offered window is at least 4 times the MSS;
  72.              * otherwise Nagle's test is sufficient to prevent SWS.
  73.               */
  74.             else if(usable < tcb->snd.wnd/4){
  75.                 usable = 0;
  76.             }
  77. #endif
  78.         }
  79.         /* Compute size of segment to send. This is either the usable
  80.          * window, the mss, or the amount we have on hand, whichever
  81.          * is less. (I don't like optimistic windows)
  82.          */
  83.         ssize = min(tcb->sndcnt - sent,usable);
  84.         ssize = min(ssize,tcb->mss);
  85.         dsize = ssize;
  86.  
  87.         if(ssize == 0 && !tcb->flags.force)
  88.             break;        /* No need to send anything */
  89.  
  90.         tcb->flags.force = 0;    /* Only one forced segment! */
  91.  
  92.         seg.source = tcb->conn.local.port;
  93.         seg.dest = tcb->conn.remote.port;
  94.  
  95.         /* Set the flags according to the state we're in. It is
  96.          * assumed that if this segment is associated with a state
  97.          * transition, then the state change will already have been
  98.          * made. This allows this routine to be called from a
  99.          * retransmission timeout with force=1.
  100.          * If SYN is being sent, adjust the dsize counter so we'll
  101.          * try to get the right amount of data off the send queue.
  102.          */
  103.         seg.flags.urg = 0; /* Not used in this implementation */
  104.         seg.flags.rst = 0;
  105.         seg.flags.ack = 1; /* Every state except SYN_SENT */
  106.         seg.flags.syn = 0; /* syn/fin/psh set later if needed */
  107.         seg.flags.fin = 0;
  108.         seg.flags.psh = 0;
  109.  
  110.         hsize = TCPLEN;    /* Except when SYN being sent */
  111.         seg.mss = 0;
  112.  
  113.         switch(tcb->state){
  114.         case SYN_SENT:
  115.             seg.flags.ack = 0;    /* Note fall-thru */
  116.         case SYN_RECEIVED:
  117.             if(tcb->snd.ptr == tcb->iss){
  118.                 seg.flags.syn = 1;
  119.                 dsize--;
  120.                 /* Also send MSS */
  121.                 seg.mss = Tcp_mss;
  122.                 hsize = TCPLEN + MSS_LENGTH;
  123.             }
  124.             break;
  125.         }
  126.         seg.seq = tcb->snd.ptr;
  127.         seg.ack = tcb->rcv.nxt;
  128.         seg.wnd = tcb->rcv.wnd;
  129.         seg.up = 0;
  130.  
  131.         /* Now try to extract some data from the send queue. Since
  132.          * SYN and FIN occupy sequence space and are reflected in
  133.          * sndcnt but don't actually sit in the send queue, dup_p
  134.          * will return one less than dsize if a FIN needs to be sent.
  135.          */
  136.         if(dsize != 0){
  137.             if(dup_p(&dbp,tcb->sndq,sent,dsize) != dsize){
  138.                 /* We ran past the end of the send queue;
  139.                  * send a FIN
  140.                  */
  141.                 seg.flags.fin = 1;
  142.                 dsize--;
  143.             }
  144.         } else {
  145.             dbp = NULLBUF;
  146. /*            dbp = alloc_mbuf(60);
  147.             dbp->data += 60; */
  148.         }
  149.         /* If the entire send queue will now be in the pipe, set the
  150.          * push flag
  151.          */
  152.         if(dsize != 0 && sent + ssize == tcb->sndcnt)
  153.             seg.flags.psh = 1;
  154.  
  155.         /* If this transmission includes previously transmitted data,
  156.          * snd.nxt will already be past snd.ptr. In this case,
  157.          * compute the amount of retransmitted data and keep score
  158.          */
  159.         if(tcb->snd.ptr < tcb->snd.nxt)
  160.             tcb->resent += min(tcb->snd.nxt - tcb->snd.ptr,ssize);
  161.  
  162.         tcb->snd.ptr += ssize;
  163.         /* If this is the first transmission of a range of sequence
  164.          * numbers, record it so we'll accept acknowledgments
  165.          * for it later
  166.          */
  167.         if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
  168.             tcb->snd.nxt = tcb->snd.ptr;
  169.  
  170.         /* Fill in fields of pseudo IP header */
  171.         ph.source = tcb->conn.local.address;
  172.         ph.dest = tcb->conn.remote.address;
  173.         ph.protocol = TCP_PTCL;
  174.         ph.length = hsize + dsize;
  175.  
  176.         /* Generate TCP header, compute checksum, and link in data */
  177.         if((hbp = htontcp(&seg,dbp,&ph)) == NULLBUF){
  178.             free_p(dbp);
  179.             return;
  180.         }
  181.         /* If we're sending some data or flags, start retransmission
  182.          * and round trip timers if they aren't already running.
  183.          */
  184.         if(ssize != 0){
  185.             /* Set round trip timer. The 3*MSPTICK term
  186.              * rounds things up, preventing unnecessary timeouts
  187.              * when the mdev and srtt values are small enough for
  188.              * truncation errors to be significant.
  189.              */
  190.             tcb->timer.start = backoff(tcb->backoff) *
  191.              (2 * tcb->mdev + tcb->srtt + 3*MSPTICK) / MSPTICK;
  192.             if(!run_timer(&tcb->timer))
  193.                 start_timer(&tcb->timer);
  194.  
  195.             /* If round trip timer isn't running, start it */
  196.             if(!tcb->flags.rtt_run){
  197.                 tcb->flags.rtt_run = 1;
  198.                 tcb->rtt_time = Clock;
  199.                 tcb->rttseq = tcb->snd.ptr;
  200.             }
  201.         }
  202.         ip_send(tcb->conn.local.address,tcb->conn.remote.address,
  203.          TCP_PTCL,tcb->tos,0,hbp,ph.length,0,0);
  204.     }
  205. }
  206.